\title{myHDL Implementation of a CIC Filter} \author{Steven K Armour} \maketitle
In [1]:
import numpy as np
np.seterr(divide='ignore', invalid='ignore')
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
#import plotly.plotly as py
#import plotly.graph_objs as go
from sympy import *
from sympy import S; Zero=S.Zero
init_printing()
import scipy.signal as sig
%matplotlib notebook
import ipywidgets as widg
from myhdl import *
from myhdlpeek import Peeker
Christopher Felton who designed the original myHDL
CIC filter found here https://github.com/jandecaluwe/site-myhdl-retired/blob/master/_ori/pages/projects/gciccomplete.txt
West Coast DSP blog article on CIC filters https://westcoastdsp.wordpress.com/2015/09/07/cascaded-integrator-comb-filters/
Target Architecture size
In [2]:
BitWidth=32
Code to read back the generated Verilog
(VHDL
) from myHDL
back into the Jupyter Notebook
In [3]:
#helper functions to read in the .v and .vhd generated files into python
def VerilogTextReader(loc, printresult=True):
with open(f'{loc}.v', 'r') as vText:
VerilogText=vText.read()
if printresult:
print(f'***Verilog modual from {loc}.v***\n\n', VerilogText)
return VerilogText
def VHDLTextReader(loc, printresult=True):
with open(f'{loc}.vhd', 'r') as vText:
VerilogText=vText.read()
if printresult:
print(f'***VHDL modual from {loc}.vhd***\n\n', VerilogText)
return VerilogText
Z-Transform preliminary math and Z-Plane graphing code
In [4]:
z, r, DisAng=symbols('z, r, Omega')
zFunc=Eq(z, r*exp(1j*DisAng)); zFunc
Out[4]:
In [5]:
zFuncN=lambdify((r, DisAng), zFunc.rhs, dummify=False)
zr=np.arange(-1.5, 1.5+.03, .03); zi=np.copy(zr)
zR, zI=np.meshgrid(zr, zi)
zN=zR+1j*zI
rN=1.0
AngThetaN=np.arange(0, 1+.005, .005)*2*np.pi
zAtR1=zFuncN(rN, AngThetaN)
In [6]:
%matplotlib notebook
def Zplot(zR, zI, HzNMag, HzAtR1NMag, HzNPhase, HzAtR1NPhase, title):
fig = plt.figure()
#plot the z space mag
axZmag = fig.add_subplot(221, projection='3d')
Mags=axZmag.plot_surface(zR, zI, HzNMag, cmap=plt.get_cmap('tab20'))
axZmag.plot(np.real(zAtR1), np.imag(zAtR1), HzAtR1NMag, 'r-', label='r=1')
axZmag.set_xlabel('Re'); axZmag.set_ylabel('Im'); axZmag.set_zlabel('Mag')
axZmag.legend(loc='best')
fig.colorbar(Mags)
#plot the z space phase
axZph = fig.add_subplot(222, projection='3d')
Phase=axZph.plot_surface(zR, zI, HzNPhase, cmap=plt.get_cmap('tab20'))
axZph.plot(np.real(zAtR1), np.imag(zAtR1), HzAtR1NPhase, 'r-', label='r=1')
axZph.set_xlabel('Re'); axZph.set_ylabel('Im'); axZph.set_zlabel('Phase')
axZph.legend(loc='best')
fig.colorbar(Phase)
axBodeM=fig.add_subplot(212)
Mline=axBodeM.plot(AngThetaN, HzAtR1NMag, label='FTMag')
axBodeM.set_ylabel('Mag')
axBodeP=axBodeM.twinx()
Pline=axBodeP.plot(AngThetaN, np.rad2deg(HzAtR1NPhase), 'g--', label='FTPhase')
axBodeP.set_ylabel('Phase [deg]')
axBodeP.set_xlabel('Ang')
lns = Mline+Pline
labs = [l.get_label() for l in lns]
axBodeP.legend(lns, labs, loc='best')
fig.suptitle(title)
fig.show()
In [7]:
M=symbols('M')
DelayH=z**(-M); DelayH
Out[7]:
In [8]:
DelaySupH=simplify(DelayH.subs(zFunc.lhs, zFunc.rhs)); DelaySupH
Out[8]:
In [9]:
DelaySupH=simplify(DelaySupH.subs(r, 1)); DelaySupH
Out[9]:
In [10]:
DelayHN=lambdify((z, M), DelayH, dummify=False)
Mvalue=2
HzN=DelayHN(zN, M=Mvalue); HzN.shape
HzNMag=np.abs(HzN); HzNPhase=np.angle(HzN)
HAtR1=zFuncN(rN, AngThetaN)
HzAtR1N=DelayHN(zAtR1, M=Mvalue)
HzAtR1NMag=np.abs(HzAtR1N); HzAtR1NPhase=np.angle(HzAtR1N)
In [11]:
def DelayExplorer(M=1):
Mvalue=M
HzN=DelayHN(zN, M=Mvalue); HzN.shape
HzNMag=np.abs(HzN); HzNPhase=np.angle(HzN)
HAtR1=zFuncN(rN, AngThetaN)
HzAtR1N=DelayHN(zAtR1, M=Mvalue)
HzAtR1NMag=np.abs(HzAtR1N); HzAtR1NPhase=np.angle(HzAtR1N)
Zplot(zR, zI, HzNMag, HzAtR1NMag, HzNPhase, HzAtR1NPhase,
f'z Delay order M={M}')
In [12]:
# will add widgets for interative later
DelayExplorer(M=1)
In [13]:
def Delay(x, y, ena_in, clk):
'''
Z delay bulding block for a CIC filter
Inputs:
x (data): the x(n) data in feed
------------------------
ena_in (bool): the exstiror calc hold input. calc is done only if
`ena_in` is True
clk(bool): clock feed
rst(bool): reset feed
Outputs:
y (data): the y(n+1) output of y(n+1)=x(n)
'''
@always(clk. posedge)
def logic():
if ena_in:
y.next=x
return logic
In [14]:
Peeker.clear()
x=Signal(modbv(0)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(0)[BitWidth:]); Peeker(y, 'y')
ena_in, clk=[Signal(bool(0)) for _ in range(2)]
Peeker(ena_in, 'ena_in'); Peeker(clk, 'clk')
DUT=Delay(x, y, ena_in, clk)
DateCol=pd.DataFrame(columns=['x', 'y', 'ena_in'])
def Delay_TB():
@always(delay(1)) ## delay in nano seconds
def clkGen():
clk.next = not clk
@instance
def stimulus():
Tested_ena=False
count=0
while 1:
if Tested_ena==False and count<=2:
print(f'Tested_ena: {Tested_ena}, count:{count}')
elif Tested_ena==False and count>2:
print(f'Tested_ena: {Tested_ena}, count:{count}')
ena_in.next=True
Tested_ena=True
x.next=0
if Tested_ena and count>2:
x.next=x+1
if count> 2*BitWidth:
raise StopSimulation
DateCol.loc[count]=[int(x),int(y), int(ena_in)]
count+=1
yield clk.posedge
return instances()
sim = Simulation(DUT, Delay_TB(), *Peeker.instances()).run()
In [15]:
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
In [16]:
x=Signal(modbv(0)[BitWidth:])
y=Signal(modbv(0)[BitWidth:])
ena_in, clk=[Signal(bool(0)) for _ in range(2)]
toVerilog(Delay, x, y, ena_in, clk)
VerilogTextReader('Delay');
In [17]:
CombH=1-z**(-M); CombH
Out[17]:
In [18]:
CombSupH=simplify(CombH.subs(zFunc.lhs, zFunc.rhs)); CombSupH
Out[18]:
In [19]:
CombSupH=simplify(CombSupH.subs(r, 1)); CombSupH
Out[19]:
In [20]:
CombHN=lambdify((z, M), CombH, dummify=False)
def CombEx(M=2):
Mvalue=M
HzN=CombHN(zN, M=Mvalue); HzN.shape
HzNMag=np.abs(HzN); HzNPhase=np.angle(HzN)
HAtR1=zFuncN(rN, AngThetaN)
HzAtR1N=DelayHN(zAtR1, M=Mvalue)
HzAtR1NMag=np.abs(HzAtR1N); HzAtR1NPhase=np.angle(HzAtR1N)
Zplot(zR, zI, HzNMag, HzAtR1NMag, HzNPhase, HzAtR1NPhase,
f'Comb of Order M={Mvalue}')
CombEx(M=2)
In [21]:
def Comb(x, y, ena_in, ena_out, clk, rst, M=2):
'''
the comb section of a CIC filter relaying on `Delay` to create
the Z dealy blocks
Inputs:
x (data): the x(n) data in feed
------------------------
ena_in (bool): the exstiror calc hold input. calc is done only if
`ena_in` is True
clk(bool): clock feed
rst(bool): reset feed
Outputs:
y (data): the y(n) output of y(n)=y(n-1)+x(n)
----------------------
ena_out: the exstior calc hold output. will be false if
`ena_in` is False
Parm:
M: the nuumber of Z delays for this comb section
'''
#stage the the Zdelays
Zdelay_i=[None for i in range(M)]
#Parmters for sizeing the 2's comp interdaley wires
WordLen_1=len(x)-1
WireGuage=2**WordLen_1
# Create the wiring between the delays
Zwire_ij=[Signal(modbv(0, min=-WireGuage, max=WireGuage)) for j in range(M)]
#instainsate and wire togather the Zdelays
for i in range(M):
if i==0:
Zdelay_i[i]=Delay(x, Zwire_ij[i], ena_in, clk)
else:
Zdelay_i[i]=Delay(Zwire_ij[i-1], Zwire_ij[i], ena_in, clk)
#make the last delay output unieq x(M-1)
subx=Zwire_ij[M-1]
@always(clk.posedge)
def logc():
if rst:
y.next=0
else:
if ena_in:
#y=x-x(M-1)
y.next=x-subx
ena_out.next=True
else:
ena_out.next=False
return instances()
In [22]:
Peeker.clear()
x=Signal(modbv(1)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(5)[BitWidth:]); Peeker(y, 'y')
ena_in, ena_out, clk, rst=[Signal(bool(0)) for _ in range(4)]
Peeker(ena_in, 'ena_in'); Peeker(ena_out, 'ena_out'); Peeker(clk, 'clk'); Peeker(rst, 'rst')
DUT=Comb(x, y, ena_in, ena_out, clk, rst, M=2)
def Comb_TB():
@always(delay(1)) ## delay in nano seconds
def clkGen():
clk.next = not clk
@instance
def stimulus():
Tested_ena=False
Tested_rst=False
count=0
while 1:
if Tested_ena==False and count<=2:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
elif Tested_ena==False and count>2:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
ena_in.next=True
Tested_ena=True
if Tested_ena and Tested_rst==False:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
rst.next=True
Tested_rst=True
elif Tested_ena and Tested_rst and count<=4:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
rst.next=False
Tested_rst=True
x.next=1
if Tested_ena and Tested_rst and count>4:
x.next=2*(x+1)
if count> 2*BitWidth:
raise StopSimulation
count+=1
yield clk.posedge
return instances()
sim = Simulation(DUT, Comb_TB(), *Peeker.instances()).run()
In [23]:
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
In [24]:
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(5)[BitWidth:])
ena_in, ena_out, clk, rst=[Signal(bool(0)) for _ in range(4)]
toVerilog(Comb, x, y, ena_in, ena_out, clk, rst, M=2)
VerilogTextReader('Comb');
In [25]:
IntegratorH=1/(1-z**-1); IntegratorH
Out[25]:
In [26]:
IntegratorSupH=simplify(IntegratorH.subs(zFunc.lhs, zFunc.rhs))
IntegratorSupH
Out[26]:
In [27]:
IntegratorSupH=simplify(IntegratorSupH.subs(r, 1))
IntegratorSupH
Out[27]:
In [28]:
IntegratorHN=lambdify(z, IntegratorH, dummify=False)
HzN=IntegratorHN(zN); HzN.shape
HzNMag=np.abs(HzN); HzNPhase=np.angle(HzN)
HAtR1=zFuncN(rN, AngThetaN)
HzAtR1N=IntegratorHN(zAtR1)
HzAtR1NMag=np.abs(HzAtR1N); HzAtR1NPhase=np.angle(HzAtR1N)
Zplot(zR, zI, HzNMag, HzAtR1NMag, HzNPhase, HzAtR1NPhase, 'Integrator')
In [29]:
def Integrator(x, y, ena_in, ena_out, clk, rst):
'''
Simple Integrator/ Accumultor with exstior hold contorls as part
of the building blocks of a CIC filter
Inputs:
x (data): the x(n) data in feed
------------------------
ena_in (bool): the exstiror calc hold input. calc is done only if
`ena_in` is True
clk(bool): clock feed
rst(bool): reset feed
Outputs:
y (data): the y(n) output of y(n)=y(n-1)+x(n)
----------------------
ena_out: the exstior calc hold output. will be false if
`ena_in` is False
'''
@always(clk.posedge)
def logic():
if rst:
y.next=0
else:
if ena_in:
#y(n)=y(n-1)+x(n)
y.next=y+x
ena_out.next=True
else:
ena_out.next=False
return logic
In [30]:
Peeker.clear()
x=Signal(modbv(1)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(5)[BitWidth:]); Peeker(y, 'y')
ena_in, ena_out, clk, rst=[Signal(bool(0)) for _ in range(4)]
Peeker(ena_in, 'ena_in'); Peeker(ena_out, 'ena_out'); Peeker(clk, 'clk'); Peeker(rst, 'rst')
DUT=Integrator(x, y, ena_in, ena_out, clk, rst)
def Integrator_TB():
@always(delay(1)) ## delay in nano seconds
def clkGen():
clk.next = not clk
@instance
def stimulus():
Tested_ena=False
Tested_rst=False
count=0
while 1:
if Tested_ena==False and count<=2:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
elif Tested_ena==False and count>2:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
ena_in.next=True
Tested_ena=True
if Tested_ena and Tested_rst==False:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
rst.next=True
Tested_rst=True
elif Tested_ena and Tested_rst and count<=4:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
rst.next=False
Tested_rst=True
x.next=0
if Tested_ena and Tested_rst and count>4:
x.next=x+1
if count> 2*BitWidth:
raise StopSimulation
count+=1
yield clk.posedge
return instances()
sim = Simulation(DUT, Integrator_TB(), *Peeker.instances()).run()
In [31]:
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
In [32]:
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(5)[BitWidth:])
ena_in, ena_out, clk, rst=[Signal(bool(0)) for _ in range(4)]
toVerilog(Integrator, x, y, ena_in, ena_out, clk, rst)
VerilogTextReader('Integrator');
In [33]:
R, k=symbols('R, k')
X=Function('X')(z); X
Out[33]:
In [34]:
Decimator=summation(X.subs(z, z**(1/R) *exp(2j*pi*k/R)), (k, 0, R-1))/R
Decimator
Out[34]:
In [35]:
Decimator=simplify(Decimator.subs(zFunc.lhs, zFunc.rhs))
Decimator
Out[35]:
In [36]:
Decimator.subs(r, 1)
Out[36]:
In [37]:
def Decimator(x, y, ena_in, ena_out, clk, rst, R=8):
'''
A decimation (down sampling) section for a CIC filter
Inputs:
x (data): the x(n) data in feed
------------------------
ena_in (bool): the exstiror calc hold input. calc is done only if
`ena_in` is True
clk(bool): clock feed
rst(bool): reset feed
Outputs:
y (data): the y(n) output
----------------------
ena_out: the exstior calc hold output. will be false if
`ena_in` is False
Parm:
R: the decimation ratio
'''
countSize=2**np.ceil(np.log2(R))
count=Signal(intbv(0, max=countSize, min=0))
@always(clk.posedge)
def PassControl():
if rst:
y.next=0
else:
if count==0:
y.next=x
ena_out.next=True
else:
y.next=0
ena_out.next=False
@always(clk.posedge)
def CountControl():
if rst:
count.next=0
else:
if count==R-1:
count.next=0
else:
count.next=count+1
return instances()
In [38]:
Peeker.clear()
x=Signal(modbv(1)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(0)[BitWidth:]); Peeker(y, 'y')
ena_in, ena_out, clk, rst=[Signal(bool(0)) for _ in range(4)]
Peeker(ena_in, 'ena_in'); Peeker(ena_out, 'ena_out'); Peeker(clk, 'clk'); Peeker(rst, 'rst')
DUT=Decimator(x, y, ena_in, ena_out, clk, rst, R=2)
def Integrator_TB():
@always(delay(1)) ## delay in nano seconds
def clkGen():
clk.next = not clk
@instance
def stimulus():
Tested_ena=False
Tested_rst=False
count=0
while 1:
if Tested_ena==False and count<=2:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
elif Tested_ena==False and count>2:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
ena_in.next=True
Tested_ena=True
if Tested_ena and Tested_rst==False:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
rst.next=True
Tested_rst=True
elif Tested_ena and Tested_rst and count<=4:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
rst.next=False
Tested_rst=True
x.next=1
if Tested_ena and Tested_rst and count>4:
x.next=x+1
if count> 2*BitWidth:
raise StopSimulation
count+=1
yield clk.posedge
return instances()
sim = Simulation(DUT, Integrator_TB(), *Peeker.instances()).run()
In [39]:
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
In [40]:
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(0)[BitWidth:])
ena_in, ena_out, clk, rst=[Signal(bool(0)) for _ in range(4)]
toVerilog(Decimator, x, y, ena_in, ena_out, clk, rst, R=2)
VerilogTextReader('Decimator');
In [41]:
InterpolatorTheory=X.subs(z, exp(1j*DisAng*R)); InterpolatorTheory
Out[41]:
In [42]:
def Interpolator(x, y, ena_in, ena_out, clk, rst, R=8):
'''
A interpolation section for a CIC filter
Inputs:
x (data): the x(n) data in feed
------------------------
ena_in (bool): the exstiror calc hold input. calc is done only if
`ena_in` is True
clk(bool): clock feed
rst(bool): reset feed
Outputs:
y (data): the y(n) output of y(n)=y(n-1)+x(n)
----------------------
ena_out: the exstior calc hold output. will be false if
`ena_in` is False
Parm:
R: the up-sampleing ratio
'''
countSize=2**np.ceil(np.log2(R))
count=Signal(intbv(0, max=countSize, min=0))
@always(clk.posedge)
def PassControl():
if rst:
y.next=0
else:
if ena_in:
y.next=x
ena_out.next=True
elif count>0:
y.next=0
ena_out.next=True
else:
y.next=0
ena_out.next=False
@always(clk.posedge)
def CountControl():
if rst:
count.next=0
else:
if ena_in:
count.next=R-1
elif count>0:
count.next=count+1
return instances()
In [43]:
Peeker.clear()
x=Signal(modbv(1)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(0)[BitWidth:]); Peeker(y, 'y')
ena_in, ena_out, clk, rst=[Signal(bool(0)) for _ in range(4)]
Peeker(ena_in, 'ena_in'); Peeker(ena_out, 'ena_out'); Peeker(clk, 'clk'); Peeker(rst, 'rst')
DUT=Interpolator(x, y, ena_in, ena_out, clk, rst, R=2)
def Integrator_TB():
@always(delay(1)) ## delay in nano seconds
def clkGen():
clk.next = not clk
@instance
def stimulus():
Tested_ena=False
Tested_rst=False
count=0
while 1:
if Tested_ena==False and count<=2:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
elif Tested_ena==False and count>2:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
ena_in.next=True
Tested_ena=True
if Tested_ena and Tested_rst==False:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
rst.next=True
Tested_rst=True
elif Tested_ena and Tested_rst and count<=4:
print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
rst.next=False
Tested_rst=True
x.next=1
if Tested_ena and Tested_rst and count>4:
x.next=x+1
if count> 2*BitWidth:
raise StopSimulation
count+=1
yield clk.posedge
return instances()
sim = Simulation(DUT, Integrator_TB(), *Peeker.instances()).run()
In [44]:
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
In [45]:
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(0)[BitWidth:])
ena_in, ena_out, clk, rst=[Signal(bool(0)) for _ in range(4)]
toVerilog(Interpolator, x, y, ena_in, ena_out, clk, rst, R=2)
VerilogTextReader('Interpolator');
In [46]:
def PassThrough(x, y, ena_in, ena_out):
'''
A pass-throug (do nothing) section for a CIC filter
Inputs:
x (data): the x(n) data in feed
------------------------
ena_in (bool): the exstiror calc hold input. calc is done only if
`ena_in` is True
Outputs:
y (data): the y(n) output of y(n)=y(n-1)+x(n)
----------------------
ena_out: the exstior calc hold output. will be false if
`ena_in` is False
'''
@always_comb
def logic():
y.next=x
ena_out.next=ena_in
return logic
In [47]:
Peeker.clear()
x=Signal(modbv(1)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(0)[BitWidth:]); Peeker(y, 'y')
ena_in, ena_out, clk=[Signal(bool(0)) for _ in range(3)]
Peeker(ena_in, 'ena_in'); Peeker(ena_out, 'ena_out'); Peeker(clk, 'clk')
DUT=PassThrough(x, y, ena_in, ena_out)
def Integrator_TB():
@always(delay(1)) ## delay in nano seconds
def clkGen():
clk.next = not clk
@instance
def stimulus():
count=0
while 1:
if count<=5:
ena_in.next=True
elif count<=10:
ena_in.next=False
elif count>=15:
ena_in.next=True
if count> 2*BitWidth:
raise StopSimulation
x.next=x+1
count+=1
yield clk.posedge
return instances()
sim = Simulation(DUT, Integrator_TB(), *Peeker.instances()).run()
In [48]:
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
In [49]:
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(0)[BitWidth:])
ena_in, ena_out, clk=[Signal(bool(0)) for _ in range(3)]
toVerilog(PassThrough, x, y, ena_in, ena_out)
VerilogTextReader('PassThrough');
In [50]:
N=symbols('N')
CIC=simplify(((1-z**(-R*M))**N)/((1-z**(-1))**N)); CIC
Out[50]:
In [51]:
CICsub=simplify(CIC.subs(zFunc.lhs, zFunc.rhs)); CICsub
Out[51]:
In [52]:
CICN=lambdify((z, M, R, N), CIC, dummify=False)
def CICEx(N=2, M=2, R=2):
Mvalue=M; Rvalue=R; Nvalue=N
HzN=CICN(zN, M=Mvalue, R=Rvalue, N=Nvalue); HzN.shape
HzNMag=np.abs(HzN); HzNPhase=np.angle(HzN)
HAtR1=zFuncN(rN, AngThetaN)
HzAtR1N=CICN(zAtR1, M=Mvalue, R=Rvalue, N=Nvalue)
HzAtR1NMag=np.abs(HzAtR1N); HzAtR1NPhase=np.angle(HzAtR1N)
Zplot(zR, zI, HzNMag, HzAtR1NMag, HzNPhase, HzAtR1NPhase,
f'CIC Dec of N={Nvalue}, M={Mvalue}, R={Rvalue}')
CICEx()
In [53]:
def CICFilter(x, y, ena_in, ena_out, clk, rst, N=3, M=2, R=8, Type=None):
'''
The complet CIC filter
Inputs:
x (data): the x(n) data in feed
------------------------
ena_in (bool): the exstiror calc hold input. calc is done only if
`ena_in` is True
clk(bool): clock feed
rst(bool): reset feed
Outputs:
y (data): the y(n) output of y(n)=y(n-1)+x(n)
----------------------
ena_out: the exstior calc hold output. will be false if
`ena_in` is False
Parm:
N: the number of stages
M: the Z delay order
R: the decimation/Interpolation ratio
Type (None, 'Dec', 'Interp'): type of CIC filter
'''
#Parmters for sizeing the 2's comp data wires
#assumes len(x)==len(y)
WordLen_1=len(x)-1
WireGuage=2**WordLen_1
#------------------------------------------------
#create the wires from the interpoltor (or lack of) to the comb sec
#data wire
Interp_Comb_DWire=Signal(intbv(0, min=-WireGuage, max=WireGuage))
#enable wire
Interp_Comp_EWire=Signal(bool(0))
#instatiniat the interpolator (or lack of)
if Type=='Interp':
# x, y, ena_in, ena_out, clk, rst, R
Interp=Interpolator(x, Interp_Comb_DWire, ena_in, Interp_Comp_EWire, clk, rst, R)
else:
#x, y, ena_in, ena_out
Interp=PassThrough(x, Interp_Comb_DWire, ena_in, Interp_Comp_EWire)
#------------------------------------------------------------
#Data Wires
Comb_DWireIJ=[Signal(intbv(0, min=-WireGuage, max=WireGuage)) for i in range(N)]
#Enable Wires
Comb_EWireIJ=[Signal(bool(0)) for i in range(N)]
#instatintte the comb sections and wire them
Comb_i=[]
for i in range(N):
if i==0:
# x, y, ena_in, ena_out, clk, rst, M
Comb_i.append(Comb(Interp_Comb_DWire, Comb_DWireIJ[i] , Interp_Comp_EWire, Comb_EWireIJ[i], clk, rst, M))
else:
# x, y, ena_in, ena_out, clk, rst, M
Comb_i.append(Comb(Comb_DWireIJ[i-1], Comb_DWireIJ[i], Comb_EWireIJ[i-1], Comb_EWireIJ[i], clk, rst, M))
#------------------------------------------------------------
#Data Wires
Integrator_DWireIJ=[Signal(intbv(0, min=-WireGuage, max=WireGuage)) for i in range(N)]
#Enable Wires
Integrator_EWireIJ=[Signal(bool(0)) for i in range(N)]
#instatintte the integrator sections and wire them
Integrtor_i=[]
for i in range(N):
if i==0:
# x, y, ena_in, ena_out, clk, rst
Integrtor_i.append(Integrator(Comb_DWireIJ[N-1], Integrator_DWireIJ[i], Comb_EWireIJ[N-1], Integrator_EWireIJ[i], clk, rst))
else:
# x, y, ena_in, ena_out, clk, rst
Integrtor_i.append(Integrator(Integrator_DWireIJ[i-1], Integrator_DWireIJ[i], Integrator_EWireIJ[i-1], Integrator_EWireIJ[i], clk, rst))
#-------------------------------------------------------------
#instatiniat the decimator (or lack of)
if Type == 'Dec':
# x, y, ena_in, ena_out, clk, rst, R
Dec=Decimator(Integrator_DWireIJ[N-1], y, Integrator_EWireIJ[N-1], ena_out, clk, rst, R)
else:
# x, y, ena_in, ena_out
Dec=PassThrough(Integrator_DWireIJ[N-1], y, Integrator_EWireIJ[N-1], ena_out)
return instances()
In [54]:
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(0)[BitWidth:])
ena_in, ena_out, clk, rst=[Signal(bool(0)) for _ in range(4)]
toVerilog(CICFilter, x, y, ena_in, ena_out, clk, rst, N=3, M=2, R=8, Type=None)
VerilogTextReader('CICFilter');